#ifndef CSHARP_GENERATOR_H
#define CSHARP_GENERATOR_H

#include "code_generator.h"

#include <fstream>
#include <map>
#include <set>

namespace pp
{
    class CSharpGenerator : public CodeGenerator
    {
    private:
        std::string m_sNameSpace;                               // namespace，如果为空，则使用m_sPackage
        std::map<std::string, std::string> m_oConstMap;         // 常量所在类
        std::string m_sJsonType;                                // 支持的json类型
        std::set<std::string> m_oEnumList;                      // 枚举，key: package.enumName
    public:
        CSharpGenerator(const std::string& srcdir, const std::string& outdir) : CodeGenerator(srcdir, outdir) {}
    public:
        // 重置数据
        virtual void Reset(const std::string& srcfile); // srcfile是pp定义文件名
        // 处理pp文件中的import定义
        virtual void HandleImport(const std::string& imports);
        // 处理pp文件中的option定义，忽略不支持的option。比如option go_package是一个option
        virtual void HandleOption(const std::string& name, const std::string& value);
        // 处理pp文件中的常量定义
        virtual void HandleConst(const std::shared_ptr<FieldInfo>& fieldInfo);
        // 处理pp文件中的enum定义
        virtual void HandleEnum(const std::shared_ptr<StructInfo>& structInfo);
        // 处理pp文件中的message定义
        virtual void HandleStruct(const std::shared_ptr<StructInfo>& structInfo);
        // 生成文件
        virtual void Generate();
    protected:
        // 宏定义和枚举，独立一个文件
        void GenerateConstFile(const std::string& outdir);
        // 宏定义
        void GenerateConst(std::ofstream& ofs, const std::string& constname);
        // 枚举定义
        void GenerateEnum(std::ofstream& ofs);
        // 枚举值
        void GenerateEnumValues(std::ofstream& ofs, const std::string& enumName, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // 生成class文件，每个message一个文件
        void GenerateClassFile(const std::string& outdir);
        // 生成using
        void GenerateImports(std::ofstream& ofs);
        // 消息成员定义
        void GenerateClassAttributes(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // 构造函数
        void GenerateClassConstructor(std::ofstream& ofs, const std::string& className, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // 编码函数
        void GenerateClassEncodeFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // 解码函数
        void GenerateClassDecodeFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // ToJson函数
        void GenerateClassToJsonFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // ToString函数
        void GenerateClassToStringFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // FromJson函数
        void GenerateClassFromJsonFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // Json类消息成员定义
        void GenerateJsonClassAttributes(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // Json类构造函数
        void GenerateJsonClassConstructor(std::ofstream& ofs, const std::string& className, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // 命名空间
        void GenerateNamespace(std::ofstream& ofs);
    protected:
        // 命名空间
        std::string GetNameSpace() {return m_sNameSpace.empty() ? GetPascalName(m_sPackage) : GetPascalName(m_sNameSpace);}
        // 命名空间产生的缩进
        std::string GetNameSpaceIndentation() {return GetNameSpace().empty() ? "" : CODE_INDENTATION;}
        // 返回数据类型
        std::string GetClassType(const std::string& ftype);
        // 获取常量文件名
        std::string GetConstFile();
        // 获取pascalname
        std::string GetPascalName(const std::string& name, bool package = true);
        // 返回类成员定义
        std::string GetClassAttribute(const std::string& ftype, const std::string& subtype, const std::string& name);
        // 返回Json类成员定义
        std::string GetJsonClassAttribute(const std::string& ftype, const std::string& subtype, const std::string& name);
        // 获取常量配置
        const std::map<std::string, std::string>& GetConstMap() const {return m_oConstMap;}
        // 引入其他PP文件定义的常量、message(常量可以在tag，default，size等属性中使用)
        std::string GetImportValue(const std::string& constVal, bool bstring = false, const std::string& ftype = "ulong",
            const std::string& attr = "");
        // 把包头去掉
        std::string TrimImportValue(const std::string& val, const std::string& attr = "");
    };
};

#endif
